package com.yunxi.module.system.service.dept.impl;

import cn.hutool.core.collection.CollUtil;
import com.yunxi.framework.common.enums.CommonStatusEnum;
import com.yunxi.framework.common.exception.util.ServiceExceptionUtil;
import com.yunxi.framework.common.pojo.PageResult;
import com.yunxi.framework.common.util.collection.CollectionUtils;
import com.yunxi.framework.common.util.object.BeanUtils;
import com.yunxi.module.system.enums.constant.ErrorCodeConstants;
import com.yunxi.module.system.mapper.dept.PostMapper;
import com.yunxi.module.system.model.dept.PostDO;
import com.yunxi.module.system.service.dept.PostService;
import com.yunxi.module.system.vo.admin.dept.post.PostPageReqVO;
import com.yunxi.module.system.vo.admin.dept.post.PostSaveReqVO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 岗位 Service 接口实现类
 * </p>
 *
 * @author lidy
 * @since 2024-05-08
 */
@Service
@Validated
public class PostServiceImpl implements PostService {

    @Resource
    private PostMapper postMapper;

    /**
     * 根据岗位编号获得岗位信息
     *
     * @param postId 岗位ID
     * @return 岗位信息
     */
    @Override
    public PostDO getPost(Long postId) {
        return postMapper.selectById(postId);
    }

    /**
     * 获得岗位列表
     *
     * @param postIds 岗位编号数组
     * @return 岗位列表
     */
    @Override
    public List<PostDO> getPostList(Collection<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return Collections.emptyList();
        }

        return postMapper.selectBatchIds(postIds);
    }

    /**
     * 获得符合条件的岗位列表
     *
     * @param postIds  岗位编号集合。如果为空，不进行筛选
     * @param statuses 状态数组，如果为空，不进行筛选
     * @return 岗位列表
     */
    @Override
    public List<PostDO> getPostList(Collection<Long> postIds, Collection<Integer> statuses) {
        return postMapper.selectList(postIds, statuses);
    }

    /**
     * 校验岗位是否处于开启状态
     * 以下情况，视为无效：
     * 1. 岗位编号不存在
     * 2. 岗位被禁用
     *
     * @param postIds 岗位编号集合
     */
    @Override
    public void validatePostList(Set<Long> postIds) {
        // 岗位编号集合为空
        if (CollUtil.isEmpty(postIds)) {
            return;
        }
        // 根据编号集合获得岗位集合
        List<PostDO> postDOList = postMapper.selectBatchIds(postIds);
        // 转换为 map
        Map<Long, PostDO> psotMap = CollectionUtils.convertMap(postDOList, PostDO::getId);
        // 校验
        postIds.forEach(postId -> {
            // 从 map 中获得岗位信息
            PostDO postDO = psotMap.get(postId);
            // 岗位信息为空
            if (postDO == null) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.POST_NOT_FOUND);
            }
            // 岗位被禁用
            if (!CommonStatusEnum.ENABLE.getStatus().equals(postDO.getStatus())) {
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.POST_NOT_ENABLE, postDO.getName());
            }
        });
    }

    /**
     * 获得岗位分页列表
     *
     * @param reqVO 查询条件
     * @return 岗位分页列表
     */
    @Override
    public PageResult<PostDO> getPostPage(PostPageReqVO reqVO) {
        return postMapper.selectPage(reqVO);
    }

    /**
     * 创建岗位
     *
     * @param createReqVO 岗位信息
     * @return 岗位编号
     */
    @Override
    public Long createPost(PostSaveReqVO createReqVO) {
        // 校验
        validatePostForCreateOrUpdate(null, createReqVO.getName(), createReqVO.getCode());

        // 保存
        PostDO post = BeanUtils.toBean(createReqVO, PostDO.class);
        postMapper.insert(post);
        return post.getId();
    }

    /**
     * 修改岗位
     *
     * @param updateReqVO 岗位信息
     */
    @Override
    public void updatePost(PostSaveReqVO updateReqVO) {
        // 校验
        validatePostForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getName(), updateReqVO.getCode());

        // 更新
        PostDO post = BeanUtils.toBean(updateReqVO, PostDO.class);
        postMapper.updateById(post);
    }

    /**
     * 删除岗位信息
     *
     * @param postId 岗位编号
     */
    @Override
    public void deletePost(Long postId) {
        // 校验岗位是否存在
        validatePostExists(postId);
        // 删除岗位
        postMapper.deleteById(postId);
    }

    /**
     * 校验岗位是否能新增或更新
     *
     * @param postId 岗位编号
     * @param name   岗位名称
     * @param code   岗位编码
     */
    private void validatePostForCreateOrUpdate(Long postId, String name, String code) {
        // 校验是否存在
        validatePostExists(postId);

        // 校验岗位名称唯一
        validatePostNameUnique(postId, name);

        // 校验岗位编码唯一
        validatePostCodeUnique(postId, code);
    }

    /**
     * 校验岗位的唯一性
     *
     * @param postId 岗位编号
     * @param code   岗位编码
     */
    private void validatePostCodeUnique(Long postId, String code) {
        // 根据岗位编码查询
        PostDO postDO = postMapper.selectByCode(code);

        if (postDO == null) {
            return;
        }
        // 如果 postId 为空，说明不用比较是否为相同 ID 的岗位
        if (postId == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.POST_NAME_DUPLICATE);
        }
        if (!postDO.getId().equals(postId)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.POST_NAME_DUPLICATE);
        }
    }

    /**
     * 校验岗位名称是否唯一
     *
     * @param postId 岗位编码
     * @param name   岗位名称
     */
    private void validatePostNameUnique(Long postId, String name) {
        // 根据岗位名称查询
        PostDO postDO = postMapper.selectByName(name);

        if (postDO == null) {
            return;
        }
        // 如果 postId 为空，说明不用比较是否为相同 ID 的岗位
        if (postId == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.POST_NAME_DUPLICATE);
        }
        if (!postDO.getId().equals(postId)) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.POST_NAME_DUPLICATE);
        }
    }

    /**
     * 校验岗位是否存在
     *
     * @param postId 岗位编号
     */
    private void validatePostExists(Long postId) {
        if (postId == null) {
            return;
        }
        if (postMapper.selectById(postId) == null) {
            throw ServiceExceptionUtil.exception(ErrorCodeConstants.POST_NOT_FOUND);
        }
    }
}
